#include <vector>

#include <logger.h>

class Calcer {
public:
    template<class T>
    int Calc(const T &that)
    {
        LOG2SO(DEBUG) << "T";
        return sizeof(that);
    }

    template<class T>
    int Calc(const std::vector<T> &vec);
};

template<class T>
int Calcer::Calc(const std::vector<T> &vec)
{
    LOG2SO(DEBUG) << "std::vector<T>";
    if (vec.capacity() == 0) {
        return 24;
    }

    auto sum = 40 + sizeof(T) * (vec.capacity() - vec.size());
    for (const auto &v : vec) {
        sum += Calc(v);
    }
    return sum;
}

struct Struct {
    int i;
    double d;
    char c;
    std::vector<int> ints;
};

template<>
int Calcer::Calc(const struct Struct &obj)
{
    LOG2SO(DEBUG) << "struct Struct";
    return sizeof(obj) + Calc(obj.ints) - sizeof(obj.ints);
}

class PrivateObject {
private:
    friend int Calcer::Calc(const PrivateObject &obj);
    std::vector<double> doubles = {1, 2, 3};
};

template<>
int Calcer::Calc(const PrivateObject &obj)
{
    LOG2SO(DEBUG) << "class PrivateObject";
    return sizeof(obj) + Calc(obj.doubles) - sizeof(obj.doubles);
}

int main()
{
    Calcer c;
    VALUE_LOGGER(c.Calc(0));
    // T
    // c.Calc(0): '4'

    std::vector<int> ints = {0, 0, 0};
    VALUE_LOGGER(c.Calc(ints));
    // std::vector<T>
    // T
    // T
    // T
    // c.Calc(ints): '52'

    std::vector<struct Struct> objs;
    objs.emplace_back();
    objs[0].ints.push_back(1);
    objs[0].ints.push_back(2);
    objs[0].ints.push_back(3);
    VALUE_LOGGER(c.Calc(objs));
    // struct Struct
    // std::vector<T>
    // T
    // T
    // T
    // c.Calc(obj): '80'

    std::vector<PrivateObject> objs2;
    objs2.emplace_back();
    VALUE_LOGGER(c.Calc(objs2));
    // std::vector<T>
    // class PrivateObject
    // std::vector<T>
    // T
    // T
    // T
    // c.Calc(objs2): '104'
    return 0;
}
